﻿#ifndef CUSTOM_LIT_INPUT_INCLUDED
#define CUSTOM_LIT_INPUT_INCLUDED

TEXTURE2D(_BaseMap);
TEXTURE2D(_MaskMap);
TEXTURE2D(_NormalMap);
TEXTURE2D(_EmissionMap);
SAMPLER(sampler_BaseMap);

TEXTURE2D(_DetailMap);
TEXTURE2D(_DetailNormalMap);
SAMPLER(sampler_DetailMap);
#if _SKIN
TEXTURE2D(_BRDFTex);
TEXTURE2D(_SSSTex);
SAMPLER(sampler_SSSTex);
#elif _SSSSS
TEXTURE2D(_SSSSSMap);
SAMPLER(sampler_SSSSSMap);
#endif

UNITY_INSTANCING_BUFFER_START(UnityPerMaterial)
	UNITY_DEFINE_INSTANCED_PROP(float4, _BaseMap_ST)
	UNITY_DEFINE_INSTANCED_PROP(float4, _DetailMap_ST)
	UNITY_DEFINE_INSTANCED_PROP(float4, _BaseColor)
	UNITY_DEFINE_INSTANCED_PROP(float4, _EmissionColor)
	UNITY_DEFINE_INSTANCED_PROP(float, _Cutoff)
	UNITY_DEFINE_INSTANCED_PROP(float, _ZWrite)
	UNITY_DEFINE_INSTANCED_PROP(float, _Metallic)
	UNITY_DEFINE_INSTANCED_PROP(float, _Occlusion)
	UNITY_DEFINE_INSTANCED_PROP(float, _Smoothness)
	UNITY_DEFINE_INSTANCED_PROP(float, _Fresnel)
	UNITY_DEFINE_INSTANCED_PROP(float, _DetailAlbedo)
	UNITY_DEFINE_INSTANCED_PROP(float, _DetailSmoothness)
	UNITY_DEFINE_INSTANCED_PROP(float, _DetailNormalScale)
	UNITY_DEFINE_INSTANCED_PROP(float, _NormalScale)
	#if _SKIN
		UNITY_DEFINE_INSTANCED_PROP(float4, _BRDFTex_ST)
		UNITY_DEFINE_INSTANCED_PROP(float4, _SSSTex_ST)
		UNITY_DEFINE_INSTANCED_PROP(half, _CurvatureScale)
		UNITY_DEFINE_INSTANCED_PROP(half, _ThicknessScale)
		UNITY_DEFINE_INSTANCED_PROP(float3, _SubColor)
		UNITY_DEFINE_INSTANCED_PROP(half, _Power)
		UNITY_DEFINE_INSTANCED_PROP(half, _Distortion)
	#elif _FABRIC
		UNITY_DEFINE_INSTANCED_PROP(half3, _FabricScatterColor)
		UNITY_DEFINE_INSTANCED_PROP(half, _FabricScatterScale)
	#elif _SSSSS
		UNITY_DEFINE_INSTANCED_PROP(half3, _SSSSScatterColor)
	#endif

	#if defined(_WINDGRASS)
		UNITY_DEFINE_INSTANCED_PROP(float4, _Wind)
		UNITY_DEFINE_INSTANCED_PROP(float, _WindEdgeFlutterFreqScale)
		UNITY_DEFINE_INSTANCED_PROP(float, _ColliderRadius)
		UNITY_DEFINE_INSTANCED_PROP(float, _PlayerForce)
		UNITY_DEFINE_INSTANCED_PROP(float, _ForceY)
	#endif

	#if defined(_VEGETATION_TREE)
		UNITY_DEFINE_INSTANCED_PROP(half, _VertAnim_Offset)
		UNITY_DEFINE_INSTANCED_PROP(half, _VertAnim_Speed)
		UNITY_DEFINE_INSTANCED_PROP(half, _VertAnim_Frequency)
		UNITY_DEFINE_INSTANCED_PROP(half, _OccAmount)
		UNITY_DEFINE_INSTANCED_PROP(float, _EmissionVal)
	#endif

	#if defined(_UVANIMATION)
		UNITY_DEFINE_INSTANCED_PROP(float, _USpeed)
		UNITY_DEFINE_INSTANCED_PROP(float, _VSpeed)
	#endif

	#if defined(_IBL)&&defined(_IBL_RP_ON)
		UNITY_DEFINE_INSTANCED_PROP(float, _IrradianceScale)
		UNITY_DEFINE_INSTANCED_PROP(float, _SpecularReflectScale)
	#endif

UNITY_INSTANCING_BUFFER_END(UnityPerMaterial)

#define INPUT_PROP(name) UNITY_ACCESS_INSTANCED_PROP(UnityPerMaterial, name)

struct InputConfig {
	Fragment fragment;
	float2 baseUV;
	float2 detailUV;
	bool useMask;
	bool useDetail;
#if defined(_SKIN)	
	float2 brdfUV;
	float2 sssUV;
#endif
};

#if _SKIN
InputConfig GetInputConfig (float4 positionSS, float2 baseUV, float2 detailUV = 0.0, float2 brdfUV = 0.0, float2 sssUV = 0.0) 
#else
InputConfig GetInputConfig(float4 positionSS, float2 baseUV, float2 detailUV = 0.0) 
#endif
{
	InputConfig c;
	c.fragment = GetFragment(positionSS);
	c.baseUV = baseUV;
	c.detailUV = detailUV;
	c.useMask = false;
	c.useDetail = false;
#if defined(_SKIN)	
	c.brdfUV = baseUV;
	c.sssUV = baseUV;
#endif
	return c;
}

#if defined(_UVANIMATION)
float GetUSpeed()
{
	return INPUT_PROP(_USpeed);
}

float GetVSpeed()
{
	return INPUT_PROP(_VSpeed);
}
#endif

float2 TransformBaseUV (float2 baseUV) {
	float4 baseST = INPUT_PROP(_BaseMap_ST);
	#if defined(_UVANIMATION)
		baseST.zw += float2(_Time.x * GetUSpeed(), _Time.y * GetVSpeed());
	#endif
	return baseUV * baseST.xy + baseST.zw;
}

float2 TransformDetailUV (float2 detailUV) {
	float4 detailST = INPUT_PROP(_DetailMap_ST);
	return detailUV * detailST.xy + detailST.zw;
}

float4 GetMask (InputConfig c) {
	if (c.useMask) {
		return SAMPLE_TEXTURE2D(_MaskMap, sampler_BaseMap, c.baseUV);
	}
	return 1.0;
}

float4 GetDetail (InputConfig c) {
	if (c.useDetail) {
		float4 map = SAMPLE_TEXTURE2D(_DetailMap, sampler_DetailMap, c.detailUV);
		return map * 2.0 - 1.0;
	}
	return 0.0;
}

float4 GetBase (InputConfig c) {
	float4 map = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, c.baseUV);
	float4 color = INPUT_PROP(_BaseColor);

	if (c.useDetail) {
		float detail = GetDetail(c).r * INPUT_PROP(_DetailAlbedo);
		float mask = GetMask(c).b;
		map.rgb =
			lerp(sqrt(map.rgb), detail < 0.0 ? 0.0 : 1.0, abs(detail) * mask);
		map.rgb *= map.rgb;
	}
	
	return map * color;
}

float GetFinalAlpha (float alpha) {
	return INPUT_PROP(_ZWrite) ? 1.0 : alpha;
}

float3 GetNormalTS (InputConfig c) {
	float4 map = SAMPLE_TEXTURE2D(_NormalMap, sampler_BaseMap, c.baseUV);
	float scale = INPUT_PROP(_NormalScale);
	float3 normal = DecodeNormal(map, scale);

	if (c.useDetail) {
		map = SAMPLE_TEXTURE2D(_DetailNormalMap, sampler_DetailMap, c.detailUV);
		scale = INPUT_PROP(_DetailNormalScale) * GetMask(c).b;
		float3 detail = DecodeNormal(map, scale);
		normal = BlendNormalRNM(normal, detail);
	}
	
	return normal;
}

float3 GetEmission (InputConfig c) {
	float4 map = SAMPLE_TEXTURE2D(_EmissionMap, sampler_BaseMap, c.baseUV);
	float4 color = INPUT_PROP(_EmissionColor);
	return map.rgb * color.rgb;
}

float GetCutoff (InputConfig c) {
	return INPUT_PROP(_Cutoff);
}

float GetMetallic (InputConfig c) {
	float metallic = INPUT_PROP(_Metallic);
	metallic *= GetMask(c).r;
	return metallic;
}

float GetOcclusion (InputConfig c) {
	float strength = INPUT_PROP(_Occlusion);
	float occlusion = GetMask(c).g;
	occlusion = lerp(occlusion, 1.0, strength);
	return occlusion;
}

float GetSmoothness (InputConfig c) {
	float smoothness = INPUT_PROP(_Smoothness);
	smoothness *= GetMask(c).a;

	if (c.useDetail) {
		float detail = GetDetail(c).b * INPUT_PROP(_DetailSmoothness);
		float mask = GetMask(c).b;
		smoothness =
			lerp(smoothness, detail < 0.0 ? 0.0 : 1.0, abs(detail) * mask);
	}
	
	return smoothness;
}

float GetFresnel (InputConfig c) {
	return INPUT_PROP(_Fresnel);
}

#if _SKIN
float2 TransformBRDFUV(float2 brdfUV)
{
	float4 brdfST = INPUT_PROP(_BRDFTex_ST);
	return brdfUV * brdfST.xy + brdfST.zw;
}

float2 TransformSSSUV(float2 sssUV)
{
	float4 sssST = INPUT_PROP(_SSSTex_ST);
	return sssUV * sssST.xy + sssST.zw;
}

float4 GetBRDFData(float4 brdfUV)
{
	float4 map = SAMPLE_TEXTURE2D(_BRDFTex, sampler_SSSTex, brdfUV);
	return map;
}

half GetCurvature(InputConfig c)
{
	float4 map = SAMPLE_TEXTURE2D(_SSSTex, sampler_SSSTex, c.sssUV);
	float curvatureScale = INPUT_PROP(_CurvatureScale);
	return map.r * curvatureScale;
}

half GetThickness(InputConfig c)
{
	float4 map = SAMPLE_TEXTURE2D(_SSSTex, sampler_SSSTex, c.sssUV);
	return map.g;
}

half GetThicknessScale(InputConfig c)
{
	return INPUT_PROP(_ThicknessScale);
}


float3 GetSubColor()
{
	return INPUT_PROP(_SubColor);
}

half GetPower()
{
	return INPUT_PROP(_Power);
}

half GetDistortion()
{
	return INPUT_PROP(_Distortion);
}
#elif _FABRIC

half3 GetFabricScatterColor()
{
	return INPUT_PROP(_FabricScatterColor);
}

half GetScatterScale()
{
	return INPUT_PROP(_FabricScatterScale);
}
#elif _SSSSS
float4 GetSSSSScatterColor(float4 scatterUV)
{
	float4 map = SAMPLE_TEXTURE2D(_SSSSSMap, sampler_SSSSSMap, scatterUV);
	float4 color = float4(INPUT_PROP(_SSSSScatterColor), 1);
	return color + map;
}
#endif

#if defined(_WINDGRASS)
float4 GetWind()
{
	return INPUT_PROP(_Wind);
}

float GetWindEdgeFlutterFreqScale()
{
	return INPUT_PROP(_WindEdgeFlutterFreqScale);
}

float GetColliderRadius()
{
	return INPUT_PROP(_ColliderRadius);
}

float GetPlayerForce()
{
	return INPUT_PROP(_PlayerForce);
}

float GetForceY()
{
	return INPUT_PROP(_ForceY);
}
#endif


#if defined(_VEGETATION_TREE)
half GetVertAnim_Offset()
{
	return INPUT_PROP(_VertAnim_Offset);
}

half GetVertAnim_Speed()
{
	return INPUT_PROP(_VertAnim_Speed);
}

half GetVertAnim_Frequency()
{
	return INPUT_PROP(_VertAnim_Frequency);
}

half GetOccAmount()
{
	return INPUT_PROP(_OccAmount);
}

float GetEmissionVal()
{
	return INPUT_PROP(_EmissionVal);
}

#endif


#if defined(_IBL)&&defined(_IBL_RP_ON)
float GetIrradianceScale()
{
	return INPUT_PROP(_IrradianceScale);
}

float GetSpecularReflectScale()
{
	return INPUT_PROP(_SpecularReflectScale);
}
#endif

#endif